限界分支法(队列方式)追踪解:01背包问题

102 篇文章 0 订阅
70 篇文章 0 订阅

追踪解

追踪解,上述实现的情况下,解都在最后一层,根本不知道之前的路径是怎样的,广度优先搜索,同一个纬度,假如不加指标判断的话,根本不知道最优解是选择的哪一个,所以需要同一个纬度的每一个结点,记住他之前的路径,才能在最优解的时候之前是怎么走过来的,每一个结点用一个数组记录路径,这样实现的感觉消耗有点大啊,通常看见是采用链表方式

限界分支法本质还是空间树,树的话,还是用链表实现比较容易和直观

把之前实现基于数组的形式修改成结点链表方式

实现如下:

#%%
# 修改成结点,为了追踪解,新增两个变量,是否选择物品和前一个物品的结点
class Node:
    def __init__(self, CurCost=None,CurValue=None,Flag=None,parent=None):
        # 部分解所占体积
        self.CurCost = CurCost
        # 部分解所占价值
        self.CurValue = CurValue
        # 当前结点是否选择了物品
        self.isleft = Flag
        # 前一个结点是谁
        self.parent = parent

        
class FIFO_01_Pack_with_solution_tracking:
    def __init__(self,N,V,C,W):
        self.num =N
        self.Volume = V
        self.Cost = C
        self.Value = W
        # 存放最优解
        self.BestResult = [False]*N
#       最优解结点,这里是叶子结点
        self.BestNode = Node(0,0,False,None)
        
        #用于存放活结点,便于理解,把根结点,以及第0层结束标志-1放进去
        # 结点包括2个属性:当前空间大小,当前的价值大小
        self.queue = [Node(0,0,False,None),Node(-1,-1,False,None),]  

    # 实现时叶子结点不加入到活结点列表,当属于叶子结点时,增加对结果的处理
    def enQueen(self,node,depth):
        if depth == self.num -1:
            CurValue = node.CurValue
            if CurValue > self.BestNode.CurValue:
                self.BestNode.CurValue = CurValue
                self.BestNode.isleft = node.isleft
                self.BestNode.parent = node.parent               
        else:
            self.queue.append(node)
            
    def pack_01(self):
#        selected = [0]*self.num      
        # 首先取出根结点
        depth = 0
        node = self.queue.pop(0)
        CurCost = node.CurCost
        CurValue = node.CurValue
        
        while True:
            # 判断左结点能否加入到队列,能的话,把当前空间和当前价值放入队列
            if CurCost + self.Cost[depth] < self.Volume:
                # 这时的父节点就是node
                self.enQueen(Node(CurCost + self.Cost[depth],CurValue + self.Value[depth],True,node),depth)
            # 右结点总是可以加入队列的,因为没有约束条件的限制
            self.enQueen(Node(CurCost,CurValue,False,node),depth)
            
            # 然后弹出下一个结点
            node = self.queue.pop(0)
            CurCost = node.CurCost
            CurValue = node.CurValue
            
            # 当同一层处理完毕时,先判断是否能够输出结果,判断的标准是队列是否为空,
            # 这时下一层的所有结点已经加入了队列,这时需要把下一层
            # 增加一个结尾-1便于判断,然后进入下一层,弹出下一个结点
            if CurCost == -1:
                if not self.queue:
                    return self.BestNode.CurValue
                self.enQueen(Node(-1,-1,False,None),depth)
                depth += 1
                node = self.queue.pop(0)
                CurCost = node.CurCost
                CurValue = node.CurValue
    
    def solution_Tracking(self):
        #追踪解从self.BestNode开始追踪
        for j in range(self.num-1,-1,-1):
            self.BestResult[j] = self.BestNode.isleft
            self.BestNode = self.BestNode.parent
        return self.BestResult
        
            
    def print_Result(self):
        print(self.pack_01())
        print(self.solution_Tracking())
        

N = 8
V = 30
C = [11,2,3,9,13,6,15,7,19]
W = [5.0,2.0,5.0,7.0,5.0,11.0,6.0,14.0]

FIFO_01_Pack_with_solution_tracking(N,V,C,W).print_Result()

39.0
[False, True, True, True, False, True, False, True]
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用C++实现优先队列分支限界0-1背包问题的代码: ```c++ #include <iostream> #include <queue> #include <algorithm> using namespace std; struct Node { int level; // 当前节点所在的层数 int profit; // 当前节点的价值 int weight; // 当前节点的重量 double bound; // 当前节点的价值上界 }; bool operator<(const Node& a, const Node& b) { return a.bound < b.bound; } double bound(Node u, int n, int W, int* p, int* w) { if (u.weight >= W) { return 0; } double bound = u.profit; int j = u.level + 1; int totweight = u.weight; while ((j < n) && (totweight + w[j] <= W)) { totweight += w[j]; bound += p[j]; j++; } if (j < n) { bound += (W - totweight) * p[j] / w[j]; } return bound; } int knapsack(int n, int* p, int* w, int W) { priority_queue<Node> Q; Node u, v; u.level = -1; u.profit = 0; u.weight = 0; u.bound = bound(u, n, W, p, w); int maxprofit = 0; Q.push(u); while (!Q.empty()) { u = Q.top(); Q.pop(); if (u.bound > maxprofit) { v.level = u.level + 1; v.weight = u.weight + w[v.level]; v.profit = u.profit + p[v.level]; if (v.weight <= W && v.profit > maxprofit) { maxprofit = v.profit; } v.bound = bound(v, n, W, p, w); if (v.bound > maxprofit) { Q.push(v); } v.weight = u.weight; v.profit = u.profit; v.bound = bound(v, n, W, p, w); if (v.bound > maxprofit) { Q.push(v); } } } return maxprofit; } int main() { int n = 5; int p[] = {3, 2, 4, 1, 5}; int w[] = {2, 1, 3, 2, 4}; int W = 7; int maxprofit = knapsack(n, p, w, W); cout << "Max profit: " << maxprofit << endl; return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值